package com.yeskery.transfer.shell;

import com.yeskery.transfer.config.ConfigPropertiesKit;
import com.yeskery.transfer.config.DataBaseProperties;
import com.yeskery.transfer.core.KeyList;
import com.yeskery.transfer.core.Resource;
import com.yeskery.transfer.core.Result;
import com.yeskery.transfer.core.SproutException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.shell.Availability;
import org.springframework.shell.standard.ShellComponent;
import org.springframework.shell.standard.ShellMethod;
import org.springframework.shell.standard.ShellMethodAvailability;
import org.springframework.shell.standard.ShellOption;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.PositiveOrZero;
import java.io.File;
import java.io.IOException;

/**
 * 数据库连接信息配置的Shell
 * @author shuangjiang.du
 * @date 2018-12-12 16:27
 * @version 1.0
 */
@ShellComponent("配置数据库连接信息")
public class DataConfigShell {

	/** @see Resource */
	private final Resource resource;

	/** @see ConfigPropertiesKit */
	private final ConfigPropertiesKit configPropertiesKit;

	/**
	 * 创建数据库连接信息配置的Shell
	 * @param resource 系统资源
	 * @param configPropertiesKit 配置文件工具对象
	 */
	@Autowired
	public DataConfigShell(Resource resource, ConfigPropertiesKit configPropertiesKit) {
		this.resource = resource;
		this.configPropertiesKit = configPropertiesKit;
	}

	/**
	 * 配置服务器数据库连接信息
	 * @param host 主机
	 * @param port 端口
	 * @param database 数据库名称
	 * @param username 用户名
	 * @param password 密码
	 * @return 服务器数据库连接信息
	 */
	@ShellMethod(value = "Configure server database connection information.", key = {"config-serv", "config-server"})
	public DataBaseProperties.TransferProperties server(
			@ShellOption(value = {"--host", "--h"}, defaultValue = "localhost") String host,
			@ShellOption(value = {"--port", "--p"}, defaultValue = "3306") @PositiveOrZero Integer port,
			@ShellOption({"--database", "--db"}) @NotBlank String database,
			@ShellOption(value = {"--username", "--u"}, defaultValue = "root") String username,
			@ShellOption(value = {"--password", "--pwd"}, defaultValue = "root") String password) {
		DataBaseProperties dataBaseProperties = getDataBaseProperties();
		DataBaseProperties.TransferProperties transferProperties = getTransferProperties(dataBaseProperties
				, host, port, database, username, password);
		dataBaseProperties.setServerTransferProperties(transferProperties);
		return transferProperties;
	}

	/**
	 * 配置客户端数据库连接信息
	 * @param host 主机
	 * @param port 端口
	 * @param database 数据库名称
	 * @param username 用户名
	 * @param password 密码
	 * @return 客户端数据库连接信息
	 */
	@ShellMethod(value = "Configure client database connection information", key = {"config-cli", "config-client"})
	public DataBaseProperties.TransferProperties client(
			@ShellOption(value = {"--host", "--h"}, defaultValue = "localhost") String host,
			@ShellOption(value = {"--port", "--p"}, defaultValue = "3306") @PositiveOrZero Integer port,
			@ShellOption({"--database", "--db"}) @NotBlank String database,
			@ShellOption(value = {"--username", "--u"}, defaultValue = "root") String username,
			@ShellOption(value = {"--password", "--pwd"}, defaultValue = "root") String password) {
		DataBaseProperties dataBaseProperties = getDataBaseProperties();
		DataBaseProperties.TransferProperties transferProperties = getTransferProperties(dataBaseProperties
				, host, port, database, username, password);
		dataBaseProperties.setClientTransferProperties(transferProperties);
		return transferProperties;
	}

	/**
	 * 保存数据库连接信息到文件
	 * @param path 保存路径
	 * @return 保存数据库连接信息到文件
	 */
	@ShellMethod(value = "Save database connection information to file.", key = "config-save")
	public Result save(@ShellOption(value = {"--path", "--p"}, defaultValue = "data.properties") String path) {
		try {
			configPropertiesKit.saveConfigProperties(getDataBaseProperties(), path);
		} catch (IOException e) {
			throw new SproutException("Configuration file save failed. Check the correct path and permissions.", e);
		}
		Result result = new Result();
		result.setTitle("Save successfully");
		result.setContent("Save path: " + new File(path).getAbsolutePath());
		return result;
	}

	/**
	 * 从文件读取数据库连接信息
	 * @param path 保存路径
	 * @return 从文件读取数据库连接信息
	 */
	@ShellMethod(value = "Read database connection information from files.", key = "config-load")
	public DataBaseProperties load(@ShellOption(value = {"--path", "--p"}, defaultValue = "data.properties") String path) {
		try {
			DataBaseProperties dataBaseProperties = getDataBaseProperties();
			DataBaseProperties loadBaseProperties = configPropertiesKit.loadConfigProperties(path);
			dataBaseProperties.setServerTransferProperties(loadBaseProperties.getServerTransferProperties());
			dataBaseProperties.setClientTransferProperties(loadBaseProperties.getClientTransferProperties());
			return dataBaseProperties;
		} catch (IOException e) {
			throw new SproutException("Configuration file save failed. Check the correct path and permissions.", e);
		}
	}

	/**
	 * 查看当前的数据库连接信息
	 * @return 查看当前的数据库连接信息
	 */
	@ShellMethod(value = "View the current database connection information.", key = "config-see")
	public DataBaseProperties see() {
		return getDataBaseProperties();
	}

	/**
	 * 检查保存数据连接信息的方法
	 * @return Availability对象
	 */
	@ShellMethodAvailability({"config-save", "config-see"})
	public Availability saveAvailability() {
		DataBaseProperties dataBaseProperties = resource.get(KeyList.DATA_CONFIG_KEY, DataBaseProperties.class);
		if (dataBaseProperties == null || dataBaseProperties.getClientTransferProperties() == null
				|| dataBaseProperties.getServerTransferProperties() == null) {
			return Availability.unavailable(
					"Set up the database configuration information first.");
		}
		return Availability.available();
	}

	/**
	 * 获取数据库配置信息类
	 * @return 数据库配置类信息类
	 *
	 * @see DataBaseProperties
	 */
	private DataBaseProperties getDataBaseProperties() {
		DataBaseProperties dataBaseProperties = resource.get(KeyList.DATA_CONFIG_KEY, DataBaseProperties.class);
		if (dataBaseProperties == null) {
			dataBaseProperties = new DataBaseProperties();
			resource.add(KeyList.DATA_CONFIG_KEY, dataBaseProperties);
		}
		return dataBaseProperties;
	}

	/**
	 * 获取具体的信息对象类
	 * @param dataBaseProperties 数据库配置对象
	 * @param host 主机
	 * @param port 端口
	 * @param database 数据库名
	 * @param username 用户名
	 * @param password 密码
	 * @return 具体的信息对象类
	 *
	 * @see DataBaseProperties.TransferProperties
	 */
	private DataBaseProperties.TransferProperties getTransferProperties(DataBaseProperties dataBaseProperties,
			String host, Integer port, String database, String username, String password) {
		DataBaseProperties.TransferProperties transferProperties = dataBaseProperties.new TransferProperties();
		transferProperties.setHost(host);
		transferProperties.setPort(port);
		transferProperties.setDatabase(database);
		transferProperties.setUsername(username);
		transferProperties.setPassword(password);
		return transferProperties;
	}
}